﻿#include "ModbusTcpClient.h"
#include <QVariant>
#include <QModbusDevice>
#include <QTimer>

#pragma execution_character_set("utf-8")


ModbusTcpClient::ModbusTcpClient(const QString& name, QObject *parent)
    : PLCClientBase(name, parent)
{
    mConfig.type = PCT_ModbusTcp;
    mConfig.comConfig.tcp.mOpponentPort = 502;
    modbusDevice = new QModbusTcpClient(this);
    connect(modbusDevice, &QModbusClient::stateChanged,  this, &ModbusTcpClient::onStateChanged);
    connect(modbusDevice, &QModbusClient::errorOccurred, this, &ModbusTcpClient::onErrorOccurred);
}
ModbusTcpClient::~ModbusTcpClient()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete modbusDevice;
    modbusDevice = nullptr;
}
void ModbusTcpClient::initCom()
{
    if (!modbusDevice)
        return;
    bool intendToConnect = (modbusDevice->state() == QModbusDevice::UnconnectedState);
    if(!intendToConnect){
        modbusDevice->disconnectDevice();
    }
    QString plc_address = mConfig.comConfig.tcp.mOpponentIP + ":" + QString::number(mConfig.comConfig.tcp.mOpponentPort);
    const QUrl url = QUrl::fromUserInput(plc_address);
    //连接ip和端口 ip为QStirng类型，port为uint类型
    modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter,url.host());
    modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter,url.port());
    //连接超时和重连次数
    modbusDevice->setTimeout(2000);
    modbusDevice->setNumberOfRetries(3);
    //连接设备
    modbusDevice->connectDevice();
}


void ModbusTcpClient::sendReadData(const PLCRequestData &data)
{
    mCurDataRead = data;
    QModbusDataUnit dataUnit(mCurDataRead.table, mCurDataRead.addrStart, mCurDataRead.getAddrSize());
    auto *reply = modbusDevice->sendReadRequest(dataUnit,mConfig.serverID);
    if (reply != nullptr){
        if (!reply->isFinished()){
            connect(reply, &QModbusReply::finished, this, &ModbusTcpClient::onReadReady);
        }else{
            delete reply;
        }
    }else{
    }
}

void ModbusTcpClient::onReadReady()
{
    auto reply = qobject_cast<QModbusReply*>(sender());
    if (nullptr == reply)
        return;
    //判断是否出错
    if (reply->error() == QModbusDevice::NoError){
        PLCRequestData dataRev = mCurDataRead;
        const QModbusDataUnit responseData = reply->result();
        QList<ModbusValue> valueList = dataRev.data;
        int valueIndex = 0;
        for(int i = 0; i < valueList.size(); ++i){
            ValueType type = valueList.at(i).valueType;
            if(type == VT_Int16 || type == VT_Bool){
                valueList[i].valueI = responseData.value(valueIndex);
                valueIndex += 1;
            } else if(type == VT_Int32){
                valueList[i].valueDI = int162int32(responseData.value(valueIndex), responseData.value(valueIndex + 1));
                valueIndex += 2;
            } else if(type == VT_Float){
                valueList[i].valueF = int162float(responseData.value(valueIndex), responseData.value(valueIndex + 1));
                valueIndex += 2;
            }
        }
        dataRev.data = valueList;
        emit sigData(dataRev);
        processData(dataRev);
    }else if (reply->error() == QModbusDevice::ProtocolError){
    }else{
    }
    reply->deleteLater();
}

void ModbusTcpClient::sendWriteData(const PLCRequestData &data)
{
    mCurDataWrite = data;
    QList<ModbusValue> valueList = mCurDataWrite.data;
    QModbusDataUnit dataUnit(mCurDataWrite.table, mCurDataWrite.addrStart, mCurDataWrite.getAddrSize());
    int valueIndex = 0;
    for(int i = 0; i < valueList.size(); i++){
        ValueType type = valueList.at(i).valueType;
        if(type == VT_Int16 || type == VT_Bool){
            dataUnit.setValue(valueIndex, valueList.at(i).valueI);
            valueIndex += 1;
        } else if(type == VT_Int32){
            int16_t val1, val2;
            int32ToInt16(valueList.at(i).valueDI, val1, val2);
            dataUnit.setValue(valueIndex, val1);
            valueIndex += 1;
            dataUnit.setValue(valueIndex, val2);
            valueIndex += 1;
        }else if(type == VT_Float){
            QList<qint16> lstInt = float2int16(valueList.at(i).valueF);
            for(auto value : lstInt){
                dataUnit.setValue(valueIndex, value);
                valueIndex += 1;
            }
        }
    }
    auto *reply = modbusDevice->sendWriteRequest(dataUnit,mConfig.serverID);
    if (reply!=nullptr){
        if (!reply->isFinished()){
            connect(reply, &QModbusReply::finished,this,&ModbusTcpClient::onWriteReady);
        }else{
            delete reply;
        }
    }else{
    }
}

void ModbusTcpClient::onWriteReady()
{
    auto reply = qobject_cast<QModbusReply*>(sender());
    if (nullptr == reply){
        return;
    }
    //判断是否出错
    if (reply->error() == QModbusDevice::NoError){
    }else if (reply->error() == QModbusDevice::ProtocolError){
    }else{
    }
    reply->deleteLater();
}

void ModbusTcpClient::onStateChanged(QModbusDevice::State state)
{
    if (state == QModbusDevice::UnconnectedState){
        setPLCState(CS_UnConnected);
    }else if (state == QModbusDevice::ConnectedState){
        setPLCState(CS_Connected);
    }
}
void ModbusTcpClient::onErrorOccurred(QModbusDevice::Error newError)
{
    if (newError == QModbusDevice::NoError || !modbusDevice)
        return;
    emit sigErrOccur(modbusDevice->errorString());
}
